-- $Id: $
-- File name:   MEMORY_CONTROLLER.vhd
-- Created:     4/13/2011
-- Author:      Brandon Blaine Gardner
-- Lab Section: 337-06
-- Version:     1.0  Initial Design Entry
-- Description: This is the memory controller block for the HD Audio codec.

-- TODO:
-- 
-- 158 flip-flops!  HOLY SHIT!!!
-- 

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_arith.ALL;
USE IEEE.std_logic_unsigned.ALL;

entity MEMORY_CONTROLLER is
	port(
		CLK : in std_logic;
		RST : in std_logic; -- Active Low
		--SYNC : in std_logic;
		EN : out std_logic;
		ERR : out std_logic; -- General error
		CRIT : out std_logic; -- Critical error
		---
		REQ_Tx_DATA : out std_logic;
		Tx_DATA_STB : in std_logic;
		NEW_Rx_DATA : out std_logic;
		Rx_DATA_STB : in std_logic;
		ADDR : out std_logic_vector(11 downto 0);
		DATA_in : in std_logic_vector(7 downto 0);
		DATA_out : out std_logic_vector(7 downto 0);
		RW : out std_logic;
		RE : out std_logic;
		WE : out std_logic;
		BUSY : out std_logic;
		OWN_MEM : out std_logic;
		---
		OUTDATA : out std_logic_vector(15 downto 0);
		OUTSTRB : out std_logic;
		OUTREQ : in std_logic;
		---
		I0DATA : in std_logic_vector(15 downto 0);
		I0DRW : in std_logic;
		I0DRB : in std_logic;
		I0STRB : out std_logic;
		---
		I1DATA : in std_logic_vector(15 downto 0);
		I1DRW : in std_logic;
		I1DRB : in std_logic;
		I1STRB : out std_logic;
		---
		SYNC : in std_logic
		---
	);
end MEMORY_CONTROLLER;

architecture mcu_arch of MEMORY_CONTROLLER is

	type mainState_type is ( IDLE, ASSERT_BUSY, CRIT_ERR,
					OUT_ADDR, OUT_GET_UB, OUT_WAIT1, OUT_SET_UB, OUT_GET_LB, OUT_WAIT2, OUT_SET_LB, OUT_STB,
					IN0W_ADDR, IN0W_WRITE, IN0B_ADDR, IN0B_WRITE,
					IN1W_ADDR, IN1W_WRITE, IN1B_ADDR, IN1B_WRITE );
	
	attribute ENUM_ENCODING: STRING;
  attribute ENUM_ENCODING of mainState_type:type is 
    "10001 00000 11111 00001 00101 10101 11101 11001 11011 10011 10010 00010 01010 01000 01100 00100 10100 10000 11000";				
  -- ^IDLE ^A_B  ^C_E  ^OUT_A	                                         ^IN0W_A     ^INOB_A     ^IN1W_A     ^IN1B_A
	-- above gray counts state machine while reading/writing from/to SRAM to keep signals more stable
	
	signal mainState, nextMainState : mainState_type;
	
	type miniOUTstate_type is ( mo_wait, mo_wait_tx, mo_err );
	signal miniOUTstate, nextMiniOUTstate : miniOUTstate_type;
	
	type miniINstate_type is( mi_wait, mi_wait_rx, mi_err );
	signal miniINstate, nextMiniINstate : miniINstate_type; 
	
	-- internal EN
	signal EN_i : std_logic;
	signal EN_i_next : std_logic;
	
	-- I/O buffer delays (for not catching I/O request from IN/OUT blocks twice)
	signal outwait : std_logic_vector(2 downto 0);
	signal nextOutwait : std_logic_vector(2 downto 0);
	signal I0wait : std_logic_vector(2 downto 0);
	signal nextI0wait : std_logic_vector(2 downto 0);
	signal I1wait : std_logic_vector(2 downto 0);
	signal nextI1wait : std_logic_vector(2 downto 0);
	
	-- SRAM signals (_i denotes internal signal)
	signal address_i : std_logic_vector(11 downto 0);
	signal nextaddress_i : std_logic_vector(11 downto 0); --************fixed latch
	signal data_out_i : std_logic_vector(7 downto 0);
	signal nextdata_out_i : std_logic_vector(7 downto 0); --************fixed latch
	
	-- data Address pointers
	signal CORBaddr : std_logic_vector(11 downto 0);
	signal nextCORBaddr : std_logic_vector(11 downto 0);
	signal RIRBaddr : std_logic_vector(11 downto 0);
	signal nextRIRBaddr : std_logic_vector(11 downto 0);
	signal RIRB1addr : std_logic_vector(11 downto 0);
	signal nextRIRB1addr : std_logic_vector(11 downto 0);
	signal OUTaddr : std_logic_vector(11 downto 0);
	signal nextOUTaddr : std_logic_vector(11 downto 0);
	signal OUT2addr : std_logic_vector(11 downto 0);
	signal nextOUT2addr : std_logic_vector(11 downto 0);
	signal IN0addr : std_logic_vector(11 downto 0);
	signal nextIN0addr : std_logic_vector(11 downto 0);
	signal IN1addr : std_logic_vector(11 downto 0);
	signal nextIN1addr : std_logic_vector(11 downto 0);
	
	-- I/O counters 
	-- count # of bytes input/output this frame
	signal outByteCount : std_logic_vector(6 downto 0);
	signal nextOutByteCount : std_logic_vector(6 downto 0);
	signal IN0ByteCount : std_logic_vector(5 downto 0);
	signal nextIN0ByteCount : std_logic_vector(5 downto 0);
	signal IN1ByteCount : std_logic_vector(5 downto 0);
	signal nextIN1ByteCount : std_logic_vector(5 downto 0);
	
	-- Strobe counter (counts # of cycles SYNC is asserted
	signal SYNCcount : std_logic_vector(3 downto 0);
	signal nextSYNCcount : std_logic_vector(3 downto 0);
	
	-- 16-bit output buffer
	signal outbuf : std_logic_vector(15 downto 0);
	signal nextOutbuf : std_logic_vector(15 downto 0);
	
	-- SRAM control signals
	signal RW_i : std_logic;
	signal nextRW_i : std_logic;
  signal BUSY_i : std_logic;
  signal nextBUSY_i : std_logic;
  signal OWNMEM_i : std_logic;
  signal nextOWNMEM_i : std_logic;
  signal REQ_Tx_DATA_i : std_logic;
  signal NEW_Rx_DATA_i : std_logic;
  signal RE_i : std_logic;
  signal nextRE_i : std_logic;
  
  -- output control
  signal nextOUThold : std_logic;
  signal OUThold : std_logic;
	
begin

------------------------------------------------------------------------
--				BEGIN: Main State Machine

	mainState_reg : process( CLK, RST )
	begin
		if( RST = '0' )
		then
			---
			mainState <= IDLE;
			---
			EN_i <= '0';
			---
			outwait <= "000";
			I0wait <= "000";
			I1wait <= "000";
			---
			CORBaddr <= "000000000000"; -- 0
			RIRBaddr <= "000000111111"; -- 63
			RIRB1addr <= "000001000100"; -- 68
			OUTaddr <= "000001111111"; -- 127
			OUT2addr <= "000010111111"; -- 191
			IN0addr <= "000011111111"; -- 255
			IN1addr <= "000100111111"; -- 319
			---
			outByteCount <= "0000000";
      IN0ByteCount <= "000000";
      IN1ByteCount <= "000000";
			---
			SYNCcount <= "0000";
			---
			outbuf <= "0000000000000000";
		  ---
		  data_out_i <= "00000000";  --************fixed latch
		  address_i <= "000000000000";  --************fixed latch
		  ---
		  miniOUTstate <= mo_wait;
		  miniINstate <= mi_wait;
		  ---
		  RW_i <= '0';
      BUSY_i <= '0';
      OWNMEM_i <= '0';
      RE_i <= '0';
		  ---
		  OUThold <= '0';
		  ---
		elsif( CLK'event and CLK='1' )
		then
			---
			mainState <= nextMainState;
			---
			EN_i <= EN_i_next;
			---
			outwait <= nextOutwait;
			I0wait <= nextI0wait;
			I1wait <= nextI1wait;
			---
			CORBaddr <= nextCORBaddr;
			RIRBaddr <= nextRIRBaddr;
			RIRB1addr <= nextRIRB1addr;
			OUTaddr <= nextOUTaddr;
			OUT2addr <= nextOUT2addr;
			IN0addr <= nextIN0addr;
			IN1addr <= nextIN1addr;
			---
			outByteCount <= nextOutByteCount;
	    IN0ByteCount <= nextIN0ByteCount;
	    IN1ByteCount <= nextIN1ByteCount;
			---
			SYNCcount <= nextSYNCcount;
			---
			outbuf <= nextOutbuf;
			---
			address_i <= nextaddress_i; --************fixed latch
			data_out_i <= nextdata_out_i; --************fixed latch
			---
			miniOUTstate <= nextMiniOUTstate;
		  miniINstate <= nextMiniINstate;
		  ---
		  RW_i <= nextRW_i;
      BUSY_i <= nextBUSY_i;
      OWNMEM_i <= nextOWNMEM_i;
      RE_i <= nextRE_i;
		  ---
		  OUThold <= nextOUThold;
		  ---
		end if;
	end process mainState_reg;
	
	mainState_nsl : process( mainState, EN_i, outwait, I0wait, I1wait,
										OUTREQ, I0DRW, I0DRB, I1DRW, I1DRB,
										Tx_DATA_STB, Rx_DATA_STB,
										data_out_i, address_i,
										miniINstate, miniOUTstate,
										I0DATA, I1DATA,
								    DATA_in,
								    outbuf,
								    IN0ByteCount, IN1ByteCount, outByteCount,
								    CORBaddr, RIRBaddr, RIRB1addr, OUTaddr, OUT2addr, IN0addr, IN1addr,
								    OWNMEM_i, RW_i, BUSY_i )
	begin
	
	nextMainState <= mainState;
	---
	EN_i_next <= EN_i;
	ERR <= '0';
	CRIT <= '0';
	--BUSY <= '0';
	--OWN_MEM <= '0';
	--RW <= '0'; -- default to write mode
	--RE <= '0';
	WE <= '0';
	OUTSTRB <= '0';
	I0STRB <= '0';
	I1STRB <= '0';
	---
	nextOutwait <= outwait;
	nextI0wait <= I0wait;
	nextI1wait <= I1wait;
	---
	nextCORBaddr <= CORBaddr;
	nextRIRBaddr <= RIRBaddr;
	nextRIRB1addr <= RIRB1addr;
	nextOUTaddr <= OUTaddr;
	nextOUT2addr <= OUT2addr;
	nextIN0addr <= IN0addr;
	nextIN1addr <= IN1addr;
	---
	nextOutByteCount <= outByteCount;
	nextIN0ByteCount <= IN0ByteCount;
	nextIN1ByteCount <= IN1ByteCount;
	---
	nextOutbuf <= outbuf;
	---
	nextaddress_i <= address_i; --************fixed latch
	nextdata_out_i <= data_out_i; --************fixed latch
  ---
  nextMiniOUTstate <= miniOUTstate;
  nextMiniINstate <= miniINstate;
  ---
  nextRW_i <= '0'; -- these default to zero so we can set them only when they need to be '1'
  nextBUSY_i <= '0';
  nextOWNMEM_i <= '0';
  nextRE_i <= '0';
  ---
  --nextOUThold <= OUThold;
  ---
	
	if( mainState = OUT_STB )
	then
		EN_i_next <= '1';
	end if; 
	-- this sets the control of the EN signal to a register
	-- once the register is set to one, it will stay set unless CRIT_ERROR
	-- other blocks will use this value (EN) to check enable status and stuff
	
	case mainState is
	
	when IDLE =>
		if( (outwait="000" and OUTREQ='1' and OUThold = '0') OR
		    (I0wait="000" and ( I0DRW='1' or I0DRB='1' ) ) OR
		    (I1wait="000" and ( I1DRW='1' or I1DRB='1' ) )
		  )
		then
			nextMainState <= ASSERT_BUSY;
			nextBUSY_i <= '1';
		end if;
		
	when ASSERT_BUSY =>
	  nextBUSY_i <= '1';
	  nextOWNMEM_i <= '1';
		if( OUTREQ = '1' and outwait="000" and OUThold = '0' )
		then
			nextMainState <= OUT_ADDR; -- OUTPUT
			nextRW_i <= '1'; -- read mode
		elsif( I0DRW = '1' and I0wait="000" )
		then
			nextMainState <= IN0W_ADDR; -- INPUT 0 WORD
		elsif( I0DRB = '1' and I0wait="000" )
		then
			nextMainState <= IN0B_ADDR; -- INPUT 0 BYTE
		elsif( I1DRW = '1' and I1wait="000" )
		then
			nextMainState <= IN1W_ADDR; -- INPUT 1 WORD
		elsif( I1DRB = '1' and I1wait="000" )
		then
			nextMainState <= IN1B_ADDR; -- INPUT 1 BYTE
		else
			nextMainState <= IDLE; -- SOME KIND OF STROBE ERROR?
			nextBUSY_i <= '0';
			nextOWNMEM_i <= '0';
			-- set ERR? !!! NO !!!
		end if;
	  
	------------------------
	-- OUT BLOCK PROCESSING	
	when OUT_ADDR =>
		nextBUSY_i <= '1';
		nextOWNMEM_i <= '1';
		nextRW_i <= '1'; -- read mode
		nextRE_i <= '1'; -- read next cycle
		if( outByteCount>"0000100" and outByteCount<"0100101")
		then
			nextaddress_i <= OUTaddr; --************fixed latch
		elsif( outByteCount>="0100101" )
		then
			nextaddress_i <= OUT2addr; --************fixed latch
		elsif( outByteCount <= "0000100" )
		then
			nextaddress_i <= CORBaddr; --************fixed latch
		end if; -- set ADDR to CORB(0-4) or OUT(5-36) or OUT2(37+) ptr
		nextMainState <= OUT_GET_UB;
		
	when OUT_GET_UB =>
		nextBUSY_i <= '1';
		nextOWNMEM_i <= '1';
		nextRE_i <= '1'; -- read next cycle
	  --RE <= '1'; -- strobe RE
		nextRW_i <= '1'; -- read mode
		nextOutByteCount <= outByteCount + 1; -- increment outByteCount
		if( outByteCount>"0000100" and outBytecount<"0100101" )
		then -- inc OUT when >4 and <37
			nextOUTaddr <= OUTaddr + 1;
		elsif( outByteCount >="0100101" )
		then -- inc OUT2 when >=37
			nextOUT2addr <= OUT2addr + 1;
		elsif( outByteCount <= "0000100" )
		then -- inc CORB when <= 4
			nextCORBaddr <= CORBaddr + 1;
		end if; -- inc CORB(0-4) or OUT(5-36) or OUT2(37+) ptr
		nextMainState <= OUT_WAIT1;
	
	when OUT_WAIT1 =>		--*********extra wait time for SRAM
	  nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    nextRE_i <= '1'; -- read next cycle
    --RE <= '1'; -- strobe RE
    nextRW_i <= '1'; -- read mode
    nextMainState <= OUT_SET_UB;

	when OUT_SET_UB =>
		nextBUSY_i <= '1';
		nextOWNMEM_i <= '1';
		nextRE_i <= '1'; -- read next cycle
		--RE <= '1';
		nextRW_i <= '1'; -- read mode
		nextOutbuf(15 downto 8) <= DATA_in; -- set DATA on out buffer
		if( outByteCount>"0000100" and outByteCount<"0100101")
		then
			nextaddress_i <= OUTaddr; --************fixed latch
		elsif( outByteCount>="0100101" )
		then
			nextaddress_i <= OUT2addr; --************fixed latch
		elsif( outByteCount <= "0000100" )
		then
			nextaddress_i <= CORBaddr; --************fixed latch
		end if; -- set ADDR to CORB(0-4) or OUT(5-36) or OUT2(37+) ptr
		nextMainState <= OUT_GET_LB;
		
	when OUT_GET_LB =>
		nextBUSY_i <= '1';
		nextOWNMEM_i <= '1';
		nextRE_i <= '1'; -- read next cycle
		--RE <= '1'; -- strobe RE
		nextRW_i <= '1'; -- read mode
		nextOutByteCount <= outByteCount + 1; -- increment outByteCount
		if( outByteCount>"0000100" and outBytecount<"0100101" ) --0100110
		then -- inc OUT when >4 and <37
			nextOUTaddr <= OUTaddr + 1;
		elsif( outByteCount >="0100101" and outBytecount<"1010101" )
		then -- inc OUT2 when >=37 and <85 
			nextOUT2addr <= OUT2addr + 1;
		elsif( outByteCount <= "0000100" )
		then -- inc CORB when <= 4
			nextCORBaddr <= CORBaddr + 1;
		elsif( outByteCount >= "1010101" )
		then -- rollover when 85
		  nextOutByteCount <= "0000000";
			nextCORBaddr <= "000000000000"; -- 0
			nextOUTaddr <= "000001111111"; -- 127
			nextOUT2addr <= "000010111111"; -- 191
		end if; -- inc CORB(0-4) or OUT(5-36) or OUT2(37-85) ptr [=85 rolls over]
		nextMainState <= OUT_WAIT2;
		
	when OUT_WAIT2 =>	--*********extra wait time for SRAM
	  nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    nextRE_i <= '1'; -- read next cycle 
    --RE <= '1'; -- strobe RE
    nextRW_i <= '1'; -- read mode
    nextMainState <= OUT_SET_LB;

	when OUT_SET_LB =>
	  nextBUSY_i <= '1';
	  nextOWNMEM_i <= '1';
	  -- do not read next cycle
	  --RE <= '1';
		nextRW_i <= '1'; -- read mode
		nextOutbuf(7 downto 0) <= DATA_in;
		nextMainState <= OUT_STB;
		
	when OUT_STB =>
		OUTSTRB <= '1';
		nextOutwait <= "111"; -- set next outwait downcounter
		--nextMiniOUTstate <= mo_wait_tx;
		if( (outwait="000" and OUTREQ='1' ) OR
        (I0wait="000" and ( I0DRW='1' or I0DRB='1' ) ) OR
        (I1wait="000" and ( I1DRW='1' or I1DRB='1' ) )
      )
    then
      nextMainState <= ASSERT_BUSY;
      nextBUSY_i <= '1';
      nextOWNMEM_i <= '1';
    else
      nextMainState <= IDLE;
    end if;
	--  OUT BLOCK PROCESSING	
	-------------------------
	
  -------------------------
  --  IN0 BLOCK PROCESSING
  when IN0W_ADDR =>
    nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    if( IN0ByteCount <= "000100" )
    then
      nextaddress_i <= RIRBaddr; --************fixed latch
    elsif( IN0ByteCount > "000100" )
    then
      nextaddress_i <= IN0addr; --************fixed latch
    end if; -- set ADDR to RIRB(0-4) or IN0(5+) ptr
    nextdata_out_i <= I0DATA(15 downto 8); -- set DATA from I0DATA (UB) --************fixed latch
    nextMainState <= IN0W_WRITE;
    
  when IN0W_WRITE =>
    nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    WE <= '1'; -- strobe WE
    nextIN0ByteCount <= IN0ByteCount + 1;
    if( IN0ByteCount <= "000100" )
    then -- inc RIRB when <=4
      nextRIRBaddr <= RIRBaddr + 1;
    elsif( IN0ByteCount>"000100" )
    then -- inc IN0 when >4 
      nextIN0addr <= IN0addr + 1;
    end if; -- inc RIRB(0-4) or IN0(5+) ptr
    nextMainState <= IN0B_ADDR;
    
  when IN0B_ADDR =>
    nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    if( IN0ByteCount <= "000100" )
    then
      nextaddress_i <= RIRBaddr; --************fixed latch
    elsif( IN0ByteCount > "000100" )
    then
      nextaddress_i <= IN0addr; --************fixed latch
    end if; -- set ADDR to RIRB(0-4) or IN0(5+) ptr
    nextdata_out_i <= I0DATA(7 downto 0); -- set DATA from I0DATA (LB) --************fixed latch
    nextMainState <= IN0B_WRITE;
    
  when IN0B_WRITE =>
    WE <= '1'; -- strobe WE
    I0STRB <= '1';
    nextIN0ByteCount <= IN0ByteCount + 1;
    if( IN0ByteCount <= "000100" )
    then -- inc RIRB when <= 4
      nextRIRBaddr <= RIRBaddr + 1;
    elsif( IN0ByteCount>"000100" and IN0ByteCount<"110100" )
    then -- inc IN0 when >4 and <52
      nextIN0addr <= IN0addr + 1;
    elsif( IN0ByteCount >= "110100" )
    then -- rollover when 52
      nextIN0ByteCount <= "000000";
      nextRIRBaddr <= "000000111111"; -- 63
      nextIN0addr <= "000011111111"; -- 255
    end if; -- inc RIRB(0-4) or IN0(5-52) ptr [=52 rolls over] 
    nextI0wait <= "111"; -- set I0wait downcounter
    if( (outwait="000" and OUTREQ='1' ) OR
        (I0wait="000" and ( I0DRW='1' or I0DRB='1' ) ) OR
        (I1wait="000" and ( I1DRW='1' or I1DRB='1' ) )
      )
    then
      nextMainState <= ASSERT_BUSY;
      nextBUSY_i <= '1';
      nextOWNMEM_i <= '1';
    else
      nextMainState <= IDLE;
    end if;	
  --  IN0 BLOCK PROCESSING
  -------------------------	
  
  -------------------------
  --  IN1 BLOCK PROCESSING
  when IN1W_ADDR =>
    nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    if( IN1ByteCount <= "000100" )
    then
      nextaddress_i <= RIRB1addr; --************fixed latch
    elsif( IN1ByteCount > "000100" )
    then
      nextaddress_i <= IN1addr; --************fixed latch
    end if; -- set ADDR to RIRB1(0-4) or IN1(5+) ptr
    nextdata_out_i <= I1DATA(15 downto 8); -- set DATA from I1DATA (UB) --************fixed latch
    nextMainState <= IN1W_WRITE;
    
  when IN1W_WRITE =>
    nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    WE <= '1'; -- strobe WE
    nextIN1ByteCount <= IN1ByteCount + 1;
    if( IN1ByteCount <= "000100" )
    then -- inc RIRB1 when <=4
      nextRIRB1addr <= RIRB1addr + 1;
    elsif( IN1ByteCount>"000100" )
    then -- inc IN1 when >4 
      nextIN1addr <= IN1addr + 1;
    end if; -- inc RIRB1(0-4) or IN1(5+) ptr
    nextMainState <= IN1B_ADDR;
    
  when IN1B_ADDR =>
    nextBUSY_i <= '1';
    nextOWNMEM_i <= '1';
    if( IN1ByteCount <= "000100" )
    then
      nextaddress_i <= RIRB1addr; --************fixed latch
    elsif( IN1ByteCount > "000100" )
    then
      nextaddress_i <= IN1addr; --************fixed latch
    end if; -- set ADDR to RIRB1(0-4) or IN1(5+) ptr
    nextdata_out_i <= I1DATA(7 downto 0); -- set DATA from I1DATA (LB) --************fixed latch
    nextMainState <= IN1B_WRITE;
    
  when IN1B_WRITE =>
    WE <= '1'; -- strobe WE
    I1STRB <= '1';
    nextIN1ByteCount <= IN1ByteCount + 1;
    if( IN1ByteCount <= "000100" )
    then -- inc RIRB1 when <= 4
      nextRIRB1addr <= RIRB1addr + 1;
    elsif( IN1ByteCount>"000100" and IN1ByteCount<"110100" )
    then -- inc IN1 when >4 and <52
      nextIN1addr <= IN1addr + 1;
    elsif( IN1ByteCount >= "110100" )
    then -- rollover when 52
      nextIN1ByteCount <= "000000";
      nextRIRB1addr <= "000001000100"; -- 68
      nextIN1addr <= "000100111111"; -- 319
    end if; -- inc RIRB1(0-4) or IN1(5-52) ptr [=52 rolls over] 
    nextI1wait <= "111"; -- set I1wait downcounter
    if( (outwait="000" and OUTREQ='1' ) OR
        (I0wait="000" and ( I0DRW='1' or I0DRB='1' ) ) OR
        (I1wait="000" and ( I1DRW='1' or I1DRB='1' ) )
      )
    then
      nextMainState <= ASSERT_BUSY;
      nextBUSY_i <= '1';
      nextOWNMEM_i <= '1';
    else
      nextMainState <= IDLE;
    end if;	
  --  IN1 BLOCK PROCESSING
  -------------------------	
	
	-------------------------
  --  CRIT ERR HANDLING
	when CRIT_ERR =>
	  CRIT <= '1';
	  EN_i_next <= '0';
	--  CRIT ERR HANDLING
  -------------------------
	
	end case;	
	
	------------------------------
	-- controls the i/o wait 
	-- downcounters
	-- these ensure the same out/in request is not serviced twice
	if( outwait > "000" )
	then
	  if( outwait > "101" )
	  then
	    OUTSTRB <= '1';
	  end if;
		nextOutwait <= outwait - 1;
	end if;
	
	if( I0wait > "000" )
	then
	  if( I0wait > "011" )
	  then
	    I0STRB <= '1';
	  end if;
		nextI0wait <= I0wait - 1;
	end if;
	
	if( I1wait > "000" )
	then
		nextI1wait <= I1wait - 1;
		if( I1wait > "011" )
		then
		  I1STRB <= '1';
		end if;
	end if;
	---------------------------
	
	---------------------------
	-- controls the in/out ministates
	-- these are for detecting dropped packets
	REQ_Tx_DATA_i <= '0';
	NEW_Rx_DATA_i <= '0';
	
	case miniOUTstate is
	when mo_wait =>
	  if( mainState=OUT_GET_LB and outByteCount>="1010101" )
	  then
	    nextMiniOUTstate <= mo_wait_tx;
	  end if;
	when mo_wait_tx =>
	  REQ_Tx_DATA_i <= '1';
	  if( Tx_DATA_STB = '1' )
	  then
	    nextMiniOUTstate <= mo_wait;
	  elsif( mainState = OUT_ADDR )
	  then
	    nextMiniOUTstate <= mo_err;
	  end if;
	when mo_err =>
	  ERR <= '1';
	  nextMiniOUTstate <= mo_wait;
	end case; 
    
	case miniINstate is
	when mi_wait =>
	  if( ( mainState=IN0B_WRITE and IN0ByteCount>="110100" and IN1ByteCount="000000" ) OR
	      ( mainState=IN1B_WRITE and IN1ByteCount>="110100" and IN0ByteCount="000000" )
	    )
	  then
	    nextMiniINstate <= mi_wait_rx;
	  end if;
	when mi_wait_rx =>
	  NEW_Rx_DATA_i <= '1';
	  if( Rx_DATA_STB = '1' )
	  then
	    nextMiniINstate <= mi_wait;
	  elsif( mainState=IN0W_ADDR or mainState=IN0B_ADDR or mainState=IN1W_ADDR or mainState=IN1B_ADDR )
	  then
	    nextMiniINstate <= mi_err;
	  end if;
	when mi_err =>
	  ERR <= '1';
	  nextMiniINstate <= mi_wait;
	end case;
	---------------------------
	
	---------------------------
	-- counts # of cycles sync is active
	-- increments framecount when frame sync received
	if( SYNC='1' )
	then
		nextSYNCcount <= SYNCcount + 1;
		if( SYNCcount <= "1111" ) 
		then
		  --if( NEW_Rx_DATA_i='1' )
		  --then
		    --nextNEW_Rx_DATA <= '0'; -- this sequence of events should cause the dropped packet error to blink
		    --nextREQ_Tx_DATA <= '0'; -- the output block will 
		  --end if;
			nextSYNCcount <= "1111";
		end if;
	else
		nextSYNCcount <= "0000";
	end if;
	---------------------------
	
	---------------------------
	nextOUThold <= OUThold;
	if( mainState=OUT_GET_LB and outByteCount>="1010101" )
	then
	  nextOUThold <= '1';
	elsif( SYNCcount >= "0110" ) -- one cycle longer than the preamble (for security)
	then
	  nextOUThold <= '0'; -- should allow for dropped packet
	end if;
	---------------------------
	
	---------------------------
	-- EXTERNALS <= internals
	EN <= EN_i;
	
	REQ_Tx_DATA <= REQ_Tx_DATA_i;
	NEW_Rx_DATA <= NEW_Rx_DATA_i;
	
	ADDR <= address_i;
	DATA_out <= data_out_i;
	
	OUTDATA <= outbuf;
	
	RW <= RW_i;
	BUSY <= BUSY_i;
	OWN_MEM <= OWNMEM_i;
	RE <= RE_i;
	
	end process mainState_nsl;
	---------------------------
	
--				END: Main State Machine
------------------------------------------------------------------------

end mcu_arch;
